package com.sh.data.engine.domain.base.model;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sh.data.engine.domain.util.ConvertUtil;
import lombok.Data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * 分页结果类
 *
 * @author: mengzheng.mhc
 * @date: 2024/5/30 17:07
 */
@Data
public class PageResult<T> implements Serializable {

    /**
     * 总记录数
     */
    private Long totalElements;

    /**
     * 结果集
     */
    private List<T> result;

    /**
     * 页数
     */
    private Integer pageNum;

    /**
     * 每页记录数
     */
    private Integer pageSize;

    /**
     * 总页数
     */
    private Integer totalPages;

    public PageResult() {
    }

    public PageResult(List<T> rows) {
        init(rows);
    }

    private void init(List<T> rows) {
        this.result = rows;
    }

    public PageResult(List<T> rows, int pageNum, int pageSize) {
        init(rows, pageNum, pageSize);
    }

    public PageResult(
            Long totalElements, List<T> result, Integer pageNum, Integer pageSize) {
        this.totalElements = totalElements;
        this.result = result;
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.totalPages = (result.size() + pageSize - 1) / pageSize;
    }

    public PageResult(List<T> rows, int pageNum, int pageSize, long total) {
        init(rows, pageNum, pageSize, total);
    }

    private void init(List<T> rows, int pageNum, int pageSize) {
        List<T> listSort = new ArrayList<>();
        long size = rows.size();
        // 截取的开始位置
        long pageStart = pageNum == 1 ? 0 : (long) (pageNum - 1) * pageSize;
        long pageEnd = Math.min(size, (long) pageNum * pageSize);
        if (size > pageStart) {
            listSort = rows.subList((int) pageStart, (int) pageEnd);
        }
        this.totalElements = size;
        this.result = listSort;
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        // 总页数
        this.totalPages = (rows.size() + pageSize - 1) / pageSize;
    }

    @Deprecated
    private void init(List<T> rows, int pageNum, int pageSize, Long total) {
        // 截取的开始位置
        this.totalElements = total;
        this.result = rows;
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        // 总页数
        this.totalPages = Math.toIntExact((total + pageSize - 1) / pageSize);
    }

    public <R> PageResult<R> convert(Function<? super T, ? extends R> mapper) {
        return ConvertUtil.convert(this, mapper);
    }

    /**
     * convert from IPage to PageResult
     *
     * @param iPage mybatis-plus page
     * @param <S>   record class
     * @return PageResult
     */
    public static <S> PageResult<S> convert(IPage<S> iPage) {
        PageResult<S> pageResult = new PageResult<>();
        pageResult.setResult(iPage.getRecords());
        pageResult.setPageNum(Math.toIntExact(iPage.getCurrent()));
        pageResult.setPageSize(Math.toIntExact(iPage.getSize()));
        pageResult.setTotalPages(Math.toIntExact(iPage.getPages()));
        pageResult.setTotalElements(iPage.getTotal());
        return pageResult;
    }

//    public static <S> PageResult<S> convert(List<S> result) {
//        PageResult<S> pageResult = new PageResult<>();
//        pageResult.setResult(result);
//        pageResult.setPageNum(Math.toIntExact(result.getCurrent()));
//        pageResult.setPageSize(Math.toIntExact(result.getSize()));
//        pageResult.setTotalPages(Math.toIntExact(result.getPages()));
//        pageResult.setTotalElements(result.getTotal());
//        return pageResult;
//    }

    /**
     * convert from IPage to PageResult, auto copy properties
     *
     * @param iPage       mybatis-plus page
     * @param targetClass convert target class
     * @param <S>         source class
     * @param <T>         record class
     * @return PageResult
     */
    public static <S, T> PageResult<T> copyPropertiesAndConvert(IPage<S> iPage, Class<T> targetClass) {
        IPage<T> convert = iPage.convert(res -> ConvertUtil.copyProperties(res, targetClass));
        return PageResult.convert(convert);
    }

    /**
     * convert from IPage to PageResult, with mapper
     *
     * @param iPage  mybatis-plus page
     * @param mapper source -> record convert mapper
     * @param <S>    source class
     * @param <T>    target class
     * @return PageResult
     */
    public static <S, T> PageResult<T> convert(IPage<S> iPage, Function<? super S, ? extends T> mapper) {
        IPage<T> convert = iPage.convert(mapper);
        return PageResult.convert(convert);
    }
}
